package cate.game.framework.timer;

import easy.java.dev.note.NoteClass;
import easy.java.dev.note.NoteField;

import java.util.LinkedList;
import java.util.Objects;
import java.util.Optional;
import java.util.function.Consumer;
import java.util.function.Supplier;

@NoteClass(value = "时间映射为任务的队列")
public class FIFOTimerSelector implements TimerSelector {

    @NoteField(value = "任务队列由")
    private final LinkedList<FIFOTimerTask> timerQueue;
    @NoteField(value = "任务列表")
    private final LinkedList<FIFOTimerTask> timerTasks;
    @NoteField(value = "处理任务")
    private final Consumer<FIFOTimerTask> queuedTaskConsumer;
    @NoteField(value = "提供循环时间间隔")
    private Supplier<Long> cycleTimeSupplier;


    public FIFOTimerSelector(LinkedList<FIFOTimerTask> timerTasks) {
        this(timerTasks, null);
    }

    public FIFOTimerSelector(LinkedList<FIFOTimerTask> timerTasks,
                             Supplier<Long> cycleTimeSupplier) {
        this(timerTasks, null, cycleTimeSupplier);
    }

    public FIFOTimerSelector(LinkedList<FIFOTimerTask> timerTasks,
                             Consumer<FIFOTimerTask> queuedTaskConsumer,
                             Supplier<Long> cycleTimeSupplier) {
        this.timerTasks = Objects.requireNonNull(timerTasks);
        this.timerQueue = new LinkedList<>(timerTasks);
        this.queuedTaskConsumer = queuedTaskConsumer;
        this.cycleTimeSupplier = cycleTimeSupplier;
    }


    @Override
    public void log() {
        Optional.ofNullable(queuedTaskConsumer)
                .ifPresent(this.timerQueue::forEach);
    }

    /**
     *根据时间选择任务
     * @param currentTimeMillis
     * @return
     */
    @Override
    public TimerTask select(Long currentTimeMillis) {
        long ms = System.currentTimeMillis();
        //通过现有任务填充timerQueue
        if (this.timerQueue.isEmpty() && !this.timerTasks.isEmpty()) {
            if (Objects.nonNull(this.cycleTimeSupplier) && cycleTimeSupplier.get() > 0) {
                this.timerTasks.stream()
                        .peek(task -> task.reset(cycleTimeSupplier.get()))
                        .forEach(this.timerQueue::offer);
                log();
            }
        }

        //如果任务到了该执行的阶段就返回该任务
        FIFOTimerTask task;
        while ((task = this.timerQueue.peek()) != null) {
            if (task.isMatch(ms)) {
                if (task.isDone()) {
                    this.timerQueue.poll();
                } else {
                    return task;
                }
            } else {
                return null;
            }
        }
        return null;
    }
}
